﻿#include "event.h"
#include "dns_base.h"
#include "qlist.h"
extern sentinel_server SOCKET_SERVER;

void* do_poll(void*  idx)
{
	int epfd_idx = *((int*)idx);
	if (epfd_idx >= EPOLL_NUM)
	{
		printf("do_sentinel_poll index out %d\n", epfd_idx);
		return NULL;
	}

    
    
	set_sock_buff(SOCKET_SERVER.client_fd[epfd_idx], 1024 * 1024);
	SOCKET_SERVER.author_fd[epfd_idx] = create_listen_ports(epfd_idx + 10000, SOCK_DGRAM, NULL, 0);
	set_sock_buff(SOCKET_SERVER.author_fd[epfd_idx], 1024 * 1024);

	SOCKET_SERVER.epfd[epfd_idx] = epoll_create(1000);

	struct epoll_event ev = { 0 };
	// 监听53
	ev.data.fd = SOCKET_SERVER.client_fd[epfd_idx];
	ev.events = EPOLLIN;        //with out EPOLLET
	epoll_ctl(SOCKET_SERVER.epfd[epfd_idx], EPOLL_CTL_ADD, ev.data.fd, &ev);

	// 监听认证服 
	ev.data.fd = SOCKET_SERVER.author_fd[epfd_idx];
	ev.events = EPOLLIN;        //with out EPOLLET
	epoll_ctl(SOCKET_SERVER.epfd[epfd_idx], EPOLL_CTL_ADD, ev.data.fd, &ev);

	struct epoll_event event[1000];
	struct epoll_event evReg;

	int i = 0;
	int ret = 0;
	char buf[512] = { 0, };
	char sndbuf[512] = { 0, };
	char ip[128] = { 0, };
	struct sockaddr_in addr;
	socklen_t len = sizeof(struct sockaddr_in);

	while (!SOCKET_SERVER.shut_server)
	{
		int numEvents = epoll_wait(SOCKET_SERVER.epfd[epfd_idx], event, 1000, 500);

		for (i = 0; i < numEvents; i++)
		{
			memset(buf, 0, 512);
			memset(sndbuf, 0, 512);
			// 53端口来的客户端请求 
			if (event[i].data.fd == SOCKET_SERVER.client_fd[epfd_idx])
			{
				if (event[i].events & EPOLLIN)
				{
					ret = recvfrom(event[i].data.fd, buf, 512, 0, (struct sockaddr*)&addr, &len);
					dns_info_t *di = create_dns_info(buf, 512);
					dns_unmarshal_info(buf, ret, di);

					unsigned char* qname = di->querys[0].qname;
					record_t* record = NULL;
					mvalue_t* cmv = NULL;
					mvalue_t *resmv = NULL;
					while (1)
					{
						record = find_record_from_temp(qname);
						if (!record)
							break;
						cmv = record->records[get_mvalue_type(CNAME)];
						if (cmv)
						{
							qname = cmv->buff;
						}
						else
							break;
					}
					resmv = get_record_from_name_type(qname, di->querys[0].par->qtype);
					if (resmv)
					{
						dns_info_t* dt = create_dns_info(sndbuf, 512);

						dt->header->ra = 1;
						dt->header->qr = 1;
						dt->header->rd = 1;

						dns_fill_query(dt, di->querys[0].qname, di->querys[0].par->qtype, CLASS_IN);
						dt->header->id = di->header->id;

						qname = di->querys[0].qname;
						while (1)
						{
							record = find_record_from_temp(qname);
							if (!record)
								break;
							cmv = record->records[get_mvalue_type(CNAME)];
							if (cmv)
							{
								dns_fill_an(dt, qname, CNAME, IN, 86400, get_mvalue_rdata_len(cmv->buff, CNAME), cmv->buff);
								qname = cmv->buff;
							}
							else
								break;
						}
						unsigned char *buff = resmv->buff;
						int i = 0;
						for (; i < resmv->num; i++)
						{
							unsigned int rdata_len = get_mvalue_rdata_len(buff, di->querys[0].par->qtype);
							dns_fill_an(dt, qname, di->querys[0].par->qtype, IN, 86400, rdata_len, buff);
							buff += rdata_len;
						}

						dns_fill_header(dt);
						int res = sendto(SOCKET_SERVER.client_fd[epfd_idx], dt->buff, dt->start, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr));
						dns_fill_header(dt);
						free_dns_info(dt);
					}
					else
					{
						request_info *pinfo = malloc(sizeof(request_info));
						init_request_info_dnspod(pinfo);
						pinfo->caddr = addr;
						pinfo->id = di->header->id;
						pinfo->qtype = di->querys[0].par->qtype;
						pinfo->cfd = SOCKET_SERVER.client_fd[epfd_idx];
						pinfo->afd = SOCKET_SERVER.author_fd[epfd_idx];
						//packet_type lowerdomain;
						check_dns_name(di->querys[0].qname, &pinfo->lowerdomain);
						strcpy(pinfo->qbuffer, pinfo->lowerdomain.domain);
						strcpy(pinfo->origin_domain, pinfo->lowerdomain.domain);
						// 						int ip_num = 0;
						// 						
						// 						// 剥
						// 						find_addr(&pinfo->lowerdomain, ip, 128, &ip_num);
						// 						// 加入qlist
						int res = insert_to_qlist(pinfo);
						if (res == -1)
							free(pinfo);
						// 						if (res != -1)
						// 						{
						// 							int j;
						// 							struct sockaddr_in aaddr;
						// 							for (j = 0; j < ip_num; ++j)
						// 							{
						// 								make_addr_from_bin(&aaddr, ip + j * 4);
						// 								aaddr.sin_port = htons(53);
						// 								query_from_auth_server_dnspod(pinfo, sndbuf, 512, &aaddr);
						// 							}
						// 						}

						// A记录找不到生成request_node开始递归
						//request_info *pinfo = malloc(sizeof(request_info));
						//init_request_info(di, pinfo);
						//pinfo->caddr = addr;
						//pinfo->qtype = di->querys[0]->par->qtype;
						//pinfo->cfd = SOCKET_SERVER.client_fd[epfd_idx];
						//packet_type lowerdomain;
						//check_dns_name(di->buff + DNS_HEADER_SIZE, &lowerdomain);
						//int ip_num = 0;
						//strcpy(pinfo->origin_domain, lowerdomain.domain);
						//find_addr(&lowerdomain, ip, 128, &ip_num);
						//int j = 0;
						//struct sockaddr_in aaddr;
						//request_node* pnode = generate_request_node(pinfo);
						//pnode->prev_chain = NULL;
						//pnode->id = di->header->id;
						////pnode->lowerdomain = lowerdomain;
						//cpy_dns_name(&pnode->lowerdomain, &lowerdomain);
						//pnode->afd = SOCKET_SERVER.author_fd[epfd_idx];

						//for (j = 0; j<ip_num; ++j)
						//{
						//	//pnode->lowerdomain = 
						//	make_addr_from_bin(&aaddr, ip + j * 4);
						//	aaddr.sin_port = htons(53);
						//	
						//	query_from_auth_server(pnode, sndbuf, 512, &aaddr);
						//}
						//if (j>0)
						//{
						//	insert_to_table(get_rnodes(), pnode->lowerdomain.label[0], pnode->lowerdomain.label_len[0], (void*)pnode, 0);
						//}
						//else
						//{
						//	free(pinfo);
						//}
					}
					free_dns_info(di);
				}
				else if (event[i].events & EPOLLOUT)
				{
				}
			}
			else
			{
				if (event[i].events & EPOLLIN)
				{
					ret = recvfrom(event[i].data.fd, buf, 512, 0, (struct sockaddr *)&addr, &len);
					dns_info_t *di = create_dns_info(buf, 512);
					dns_unmarshal_info(buf, 512, di);
					// insert kv
					insert_ns_to_dataset(di);
					if (di->header->ans_count)
					{
						insert_a_to_dataset(di, 0, di->header->ans_count);
					}
					if (di->header->add_count)
					{
						int start = di->header->ans_count + di->header->auth_count;
						int end = start + di->header->add_count;
						insert_a_to_dataset(di, start, end);
					}
					// callback
					//update_event(SOCKET_SERVER.author_fd[epfd_idx], di, sndbuf, 512);
					request_info* pinfo = find_from_qlist(di->querys[0].qname);
					if (pinfo && pinfo->cfd > 0)
					{
						// 						mvalue_t *mv = find_value_from_dataset(pinfo->qbuffer, pinfo->qtype);
						// 						if(!mv)
						// 						{
						// 							record_t * record = find_record_from_temp(pinfo->qbuffer);
						// 							if (record)
						// 								mv = record->records[get_mvalue_type(pinfo->qtype)];
						// 						}
						mvalue_t *mv = get_record_from_name_type(pinfo->qbuffer, pinfo->qtype);


						if (mv)
						{
							dns_info_t* dt = create_dns_info(sndbuf, 512);

							dt->header->ra = 1;
							dt->header->qr = 1;
							dt->header->rd = 1;

							int i = 0;

							dns_fill_query(dt, pinfo->origin_domain, pinfo->qtype, CLASS_IN);
							dt->header->id = pinfo->id;


							unsigned char * qname = pinfo->origin_domain;
							record_t* record = NULL;
							mvalue_t* cmv = NULL;
							while (1)
							{
								record = find_record_from_temp(qname);
								if (!record)
									break;
								cmv = record->records[get_mvalue_type(CNAME)];
								if (cmv)
								{
									unsigned int rdata_len = get_mvalue_rdata_len(cmv->buff, CNAME);
									dns_fill_an(dt, qname, CNAME, IN, 86400, rdata_len, cmv->buff);
									qname = cmv->buff;
								}
								else
									break;
							}
							unsigned char *buff = mv->buff;
							for (; i < mv->num; i++)
							{
								unsigned int rdata_len = get_mvalue_rdata_len(buff, pinfo->qtype);
								dns_fill_an(dt, pinfo->qbuffer, pinfo->qtype, IN, 86400, rdata_len, buff);
								buff += rdata_len;
							}

							dns_fill_header(dt);
							int res = sendto(pinfo->cfd, dt->buff, dt->start, 0, (struct sockaddr*)&pinfo->caddr, sizeof(struct sockaddr));
							dns_fill_header(dt);
							free_dns_info(dt);
							/*free(pinfo);*/
							delete_from_qlist(di->querys[0].qname, di->querys[0].qname_len, 0);
						}
					}


					free_dns_info(di);

				}
				else if (event[i].events & EPOLLOUT)
				{
				}
			}
		}
		request_info* dellist = NULL;
		request_info* addlist = NULL;
		int i = 0;
		for (; i < get_qlist()->lists_count; ++i)
		{
			node_t*node = get_qlist()->lists[i].list;
			pthread_rwlock_wrlock(&get_qlist()->lists[i].rwlock);
			for (; node != NULL; node = node->next)
			{
				request_info* pinfo = node->value;
				if (pinfo)
				{
					if (pinfo->qtimes > 50)
					{
						if (dellist)
						{
							request_info* tmp = dellist;
							while (tmp->next)
							{
								tmp = (tmp)->next;
							}
							tmp->next = pinfo;
							tmp->next->next = NULL;
						}
						else
						{
							dellist = pinfo;
							dellist->next = NULL;
						}
							
						continue;
					}

					mvalue_t* mv = get_record_from_name_type(pinfo->qbuffer, pinfo->qtype);
					if (mv)
					{
						if (pinfo->cfd > 0)
						{
							memset(sndbuf, 0, DNS_HEADER_SIZE);
							dns_info_t* dt = create_dns_info(sndbuf, 512);

							dt->header->ra = 1;
							dt->header->qr = 1;
							dt->header->rd = 1;

							int i = 0;

							dns_fill_query(dt, pinfo->origin_domain, pinfo->qtype, CLASS_IN);
							dt->header->id = pinfo->id;


							unsigned char * qname = pinfo->origin_domain;
							record_t* record = NULL;
							mvalue_t* cmv = NULL;
							while (1)
							{
								record = find_record_from_temp(qname);
								if (!record)
									break;
								cmv = record->records[get_mvalue_type(CNAME)];
								if (cmv)
								{
									unsigned len = get_mvalue_rdata_len(cmv->buff, CNAME);
									dns_fill_an(dt, qname, CNAME, IN, 86400, len, cmv->buff);
									qname = cmv->buff;
								}
								else
									break;
							}
							unsigned char *buff = mv->buff;
							for (; i < mv->num; i++)
							{
								unsigned len = get_mvalue_rdata_len(buff, pinfo->qtype);
								dns_fill_an(dt, pinfo->qbuffer, pinfo->qtype, IN, 86400, len, buff);
								buff += len;
							}

							dns_fill_header(dt);
							int res = sendto(pinfo->cfd, dt->buff, dt->start, 0, (struct sockaddr*)&pinfo->caddr, sizeof(struct sockaddr));
							dns_fill_header(dt);
							free_dns_info(dt);
							/*free(pinfo);*/

							if (dellist)
							{
								request_info* tmp = dellist;
								while (tmp->next)
								{
									tmp = (tmp)->next;
								}
								tmp->next = pinfo;
								tmp->next->next = NULL;
							}
							else
							{
								dellist = pinfo;
								dellist->next = NULL;
							}

						}
						else
						{
							++pinfo->qtimes;
						}
						continue;
					}
					++pinfo->qtimes;
					// CNAME...
					unsigned char * qname = pinfo->qbuffer;
					record_t* record = NULL;

					while (1)
					{
						mvalue_t* mv = NULL;
						record = find_record_from_temp(qname);
						if (!record)
							break;
						mv = record->records[get_mvalue_type(CNAME)];
						if (mv)
						{
							if (pinfo->cfd == 0)
							{
								int i = 0;
							}
							pinfo->hascname = 1;
							qname = mv->buff;
							//pinfo->qbuffer = qname;
						}
						else
							break;
					}
					if (qname != pinfo->qbuffer)
						strcpy(pinfo->qbuffer, qname);
					packet_type temp;
					check_dns_name(pinfo->qbuffer, &temp);
					int ip_num = 0;
					// 剥
					mv = find_addr(&temp, ip, 128, &ip_num);
					if (ip_num > 0)
					{
						int j;
						struct sockaddr_in aaddr;
						for (j = 0; j < ip_num; ++j)
						{
							make_addr_from_bin(&aaddr, ip + j * 4);
							aaddr.sin_port = htons(53);
							query_from_auth_server_dnspod(pinfo, sndbuf, 512, &aaddr);
						}
					}
					else if (mv)
					{
						int i = 0;
						unsigned char* nsname = mv->buff;
						int sz = 0;
						for (; i < mv->num; ++i)
						{
							nsname += sz;
							// NS A
							request_info *pinfo = malloc(sizeof(request_info));
							init_request_info_dnspod(pinfo);
							pinfo->caddr.sin_port = 0;
							pinfo->qtype = A;
							pinfo->cfd = 0;
							pinfo->afd = SOCKET_SERVER.author_fd[epfd_idx];
							strcpy(pinfo->qbuffer, nsname);
							strcpy(pinfo->origin_domain, nsname);
							check_dns_name(pinfo->qbuffer, &pinfo->lowerdomain);
							//int res = insert_to_qlist(pinfo);
							//if (res == -1)
								//free(pinfo);
							if (addlist)
							{
								request_info* tmp = addlist;
								while (tmp->next)
								{
									tmp = (tmp)->next;
								}
								tmp->next = pinfo;
								tmp->next->next = NULL;
							}
							else
							{
								addlist = pinfo;
								addlist->next = NULL;
							}
								

							sz = strlen(mv->buff) + 1;

						}
					}
				}
			}
			pthread_rwlock_unlock(&get_qlist()->lists[i].rwlock);
		}
		request_info* dinfo = NULL;
		while (dellist)
		{
			dinfo = dellist->next;
			delete_from_qlist(dellist->lowerdomain.label[0], dellist->lowerdomain.label_len[0], 0);
			dellist = dinfo;

 		}
		dinfo = NULL;
		while (addlist)
		{
			dinfo = addlist->next;
			int res = insert_to_qlist(addlist);
			if (res == -1)
				free(addlist);
			addlist = dinfo;

		}

		// 		if ( numEvents <=0 )   //空闲时处理 
		// 		{
		// 			ret = take_from_expire(buf,512);
		// 			if (ret <=0)
		// 				continue;
		// 			dns_info_t *di = create_dns_info(buf, 512);
		// 			dns_unmarshal_info(buf, ret, di);
		// 
		// 			request_info *pinfo = malloc(sizeof(request_info));
		// 			init_request_info(di, pinfo);
		// 			pinfo->cfd = SOCKET_SERVER.client_fd[epfd_idx];
		// 			packet_type lowerdomain;
		// 			check_dns_name(di->buff + DNS_HEADER_SIZE, &lowerdomain);
		// 			int ip_num = 0;
		// 			strcpy(pinfo->origin_domain, lowerdomain.domain);
		// 			find_addr(&lowerdomain, ip, 128, &ip_num);
		// 			int j = 0;
		// 			struct sockaddr_in aaddr;
		// 			request_node* pnode = generate_request_node(pinfo);
		// 			pnode->prev_chain = NULL;
		// 			pnode->id = di->header->id;
		// 			//pnode->lowerdomain = lowerdomain;
		// 			cpy_dns_name(&pnode->lowerdomain, &lowerdomain);
		// 			pnode->afd = SOCKET_SERVER.author_fd[epfd_idx];
		// 
		// 			for (j = 0; j < ip_num; ++j)
		// 			{
		// 				//pnode->lowerdomain = 
		// 				make_addr_from_bin(&aaddr, ip + j * 4);
		// 				aaddr.sin_port = htons(53);
		// 
		// 				query_from_auth_server(pnode, sndbuf, 512, &aaddr);
		// 			}
		// 			if (j > 0)
		// 			{
		// 				insert_to_table(get_rnodes(), pnode->lowerdomain.label[0], pnode->lowerdomain.label_len[0], (void*)pnode, 0);
		// 			}
		// 			else
		// 			{
		// 				free(pinfo);
		// 			}
		// 			free_dns_info(di);
		// 		}
	}
	return NULL;
}
